<?php

/**
 * DefinitionsApi
 * PHP version 8.3.
 *
 * @category Class
 *
 * @author   OpenAPI Generator team
 *
 * @see     https://openapi-generator.tech
 */

/**
 * Selling Partner API for Product Type Definitions.
 *
 * The Selling Partner API for Product Type Definitions provides programmatic access to attribute and data requirements for product types in the Amazon catalog. Use this API to return the JSON Schema for a product type that you can then use with other Selling Partner APIs, such as the Selling Partner API for Listings Items, the Selling Partner API for Catalog Items, and the Selling Partner API for Feeds (for JSON-based listing feeds).  For more information, see the [Product Type Definitions API Use Case Guide](doc:product-type-api-use-case-guide).
 *
 * The version of the OpenAPI document: 2020-09-01
 * Generated by: https://openapi-generator.tech
 * Generator version: 7.9.0
 */

/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

namespace SpApi\Api\productTypeDefinitions\v2020_09_01;

use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\RequestOptions;
use SpApi\ApiException;
use SpApi\AuthAndAuth\RestrictedDataTokenSigner;
use SpApi\Configuration;
use SpApi\HeaderSelector;
use SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeDefinition;
use SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeList;
use SpApi\ObjectSerializer;
use Symfony\Component\RateLimiter\LimiterInterface;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\RateLimiter\Storage\InMemoryStorage;

/**
 * DefinitionsApi Class Doc Comment.
 *
 * @category Class
 *
 * @author   OpenAPI Generator team
 *
 * @see     https://openapi-generator.tech
 */
class DefinitionsApi
{
    public ?LimiterInterface $getDefinitionsProductTypeRateLimiter;
    public ?LimiterInterface $searchDefinitionsProductTypesRateLimiter;
    protected ClientInterface $client;

    protected Configuration $config;

    protected HeaderSelector $headerSelector;

    /**
     * @var int Host index
     */
    protected int $hostIndex;

    private bool $rateLimiterEnabled;
    private InMemoryStorage $rateLimitStorage;

    /**
     * @param int $hostIndex (Optional) host index to select the list of hosts if defined in the OpenAPI spec
     */
    public function __construct(
        Configuration $config,
        ?ClientInterface $client = null,
        ?bool $rateLimiterEnabled = true,
        ?HeaderSelector $selector = null,
        int $hostIndex = 0
    ) {
        $this->config = $config;
        $this->rateLimiterEnabled = $rateLimiterEnabled;

        if ($rateLimiterEnabled) {
            $this->rateLimitStorage = new InMemoryStorage();

            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('DefinitionsApi-getDefinitionsProductType'), $this->rateLimitStorage);
            $this->getDefinitionsProductTypeRateLimiter = $factory->create('DefinitionsApi-getDefinitionsProductType');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('DefinitionsApi-searchDefinitionsProductTypes'), $this->rateLimitStorage);
            $this->searchDefinitionsProductTypesRateLimiter = $factory->create('DefinitionsApi-searchDefinitionsProductTypes');
        }

        $this->client = $client ?: new Client();
        $this->headerSelector = $selector ?: new HeaderSelector();
        $this->hostIndex = $hostIndex;
    }

    /**
     * Set the host index.
     *
     * @param int $hostIndex Host index (required)
     */
    public function setHostIndex(int $hostIndex): void
    {
        $this->hostIndex = $hostIndex;
    }

    /**
     * Get the host index.
     *
     * @return int Host index
     */
    public function getHostIndex(): int
    {
        return $this->hostIndex;
    }

    public function getConfig(): Configuration
    {
        return $this->config;
    }

    /**
     * Operation getDefinitionsProductType.
     *
     * @param string      $product_type
     *                                           The Amazon product type name. (required)
     * @param string[]    $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. Note: This parameter is limited to one marketplaceId at this time. (required)
     * @param null|string $seller_id
     *                                           A selling partner identifier. When provided, seller-specific requirements and values are populated within the product type definition schema, such as brand names associated with the selling partner. (optional)
     * @param null|string $product_type_version
     *                                           The version of the Amazon product type to retrieve. Defaults to \&quot;LATEST\&quot;,. Prerelease versions of product type definitions may be retrieved with \&quot;RELEASE_CANDIDATE\&quot;. If no prerelease version is currently available, the \&quot;LATEST\&quot; live version will be provided. (optional, default to 'LATEST')
     * @param null|string $requirements
     *                                           The name of the requirements set to retrieve requirements for. (optional, default to 'LISTING')
     * @param null|string $requirements_enforced
     *                                           Identifies if the required attributes for a requirements set are enforced by the product type definition schema. Non-enforced requirements enable structural validation of individual attributes without all the required attributes being present (such as for partial updates). (optional, default to 'ENFORCED')
     * @param null|string $locale
     *                                           Locale for retrieving display labels and other presentation details. Defaults to the default language of the first marketplace in the request. (optional, default to 'DEFAULT')
     * @param null|string $restrictedDataToken   Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getDefinitionsProductType(
        string $product_type,
        array $marketplace_ids,
        ?string $seller_id = null,
        ?string $product_type_version = 'LATEST',
        ?string $requirements = 'LISTING',
        ?string $requirements_enforced = 'ENFORCED',
        ?string $locale = 'DEFAULT',
        ?string $restrictedDataToken = null
    ): ProductTypeDefinition {
        list($response) = $this->getDefinitionsProductTypeWithHttpInfo($product_type, $marketplace_ids, $seller_id, $product_type_version, $requirements, $requirements_enforced, $locale, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getDefinitionsProductTypeWithHttpInfo.
     *
     * @param string      $product_type
     *                                           The Amazon product type name. (required)
     * @param string[]    $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. Note: This parameter is limited to one marketplaceId at this time. (required)
     * @param null|string $seller_id
     *                                           A selling partner identifier. When provided, seller-specific requirements and values are populated within the product type definition schema, such as brand names associated with the selling partner. (optional)
     * @param null|string $product_type_version
     *                                           The version of the Amazon product type to retrieve. Defaults to \&quot;LATEST\&quot;,. Prerelease versions of product type definitions may be retrieved with \&quot;RELEASE_CANDIDATE\&quot;. If no prerelease version is currently available, the \&quot;LATEST\&quot; live version will be provided. (optional, default to 'LATEST')
     * @param null|string $requirements
     *                                           The name of the requirements set to retrieve requirements for. (optional, default to 'LISTING')
     * @param null|string $requirements_enforced
     *                                           Identifies if the required attributes for a requirements set are enforced by the product type definition schema. Non-enforced requirements enable structural validation of individual attributes without all the required attributes being present (such as for partial updates). (optional, default to 'ENFORCED')
     * @param null|string $locale
     *                                           Locale for retrieving display labels and other presentation details. Defaults to the default language of the first marketplace in the request. (optional, default to 'DEFAULT')
     * @param null|string $restrictedDataToken   Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeDefinition, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getDefinitionsProductTypeWithHttpInfo(
        string $product_type,
        array $marketplace_ids,
        ?string $seller_id = null,
        ?string $product_type_version = 'LATEST',
        ?string $requirements = 'LISTING',
        ?string $requirements_enforced = 'ENFORCED',
        ?string $locale = 'DEFAULT',
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getDefinitionsProductTypeRequest($product_type, $marketplace_ids, $seller_id, $product_type_version, $requirements, $requirements_enforced, $locale);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'DefinitionsApi-getDefinitionsProductType');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getDefinitionsProductTypeRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeDefinition' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeDefinition' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeDefinition', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\productTypeDefinitions\v2020_09_01\ErrorList',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getDefinitionsProductTypeAsync.
     *
     * @param string      $product_type
     *                                           The Amazon product type name. (required)
     * @param string[]    $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. Note: This parameter is limited to one marketplaceId at this time. (required)
     * @param null|string $seller_id
     *                                           A selling partner identifier. When provided, seller-specific requirements and values are populated within the product type definition schema, such as brand names associated with the selling partner. (optional)
     * @param null|string $product_type_version
     *                                           The version of the Amazon product type to retrieve. Defaults to \&quot;LATEST\&quot;,. Prerelease versions of product type definitions may be retrieved with \&quot;RELEASE_CANDIDATE\&quot;. If no prerelease version is currently available, the \&quot;LATEST\&quot; live version will be provided. (optional, default to 'LATEST')
     * @param null|string $requirements
     *                                           The name of the requirements set to retrieve requirements for. (optional, default to 'LISTING')
     * @param null|string $requirements_enforced
     *                                           Identifies if the required attributes for a requirements set are enforced by the product type definition schema. Non-enforced requirements enable structural validation of individual attributes without all the required attributes being present (such as for partial updates). (optional, default to 'ENFORCED')
     * @param null|string $locale
     *                                           Locale for retrieving display labels and other presentation details. Defaults to the default language of the first marketplace in the request. (optional, default to 'DEFAULT')
     *
     * @throws \InvalidArgumentException
     */
    public function getDefinitionsProductTypeAsync(
        string $product_type,
        array $marketplace_ids,
        ?string $seller_id = null,
        ?string $product_type_version = 'LATEST',
        ?string $requirements = 'LISTING',
        ?string $requirements_enforced = 'ENFORCED',
        ?string $locale = 'DEFAULT'
    ): PromiseInterface {
        return $this->getDefinitionsProductTypeAsyncWithHttpInfo($product_type, $marketplace_ids, $seller_id, $product_type_version, $requirements, $requirements_enforced, $locale)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getDefinitionsProductTypeAsyncWithHttpInfo.
     *
     * @param string      $product_type
     *                                           The Amazon product type name. (required)
     * @param string[]    $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. Note: This parameter is limited to one marketplaceId at this time. (required)
     * @param null|string $seller_id
     *                                           A selling partner identifier. When provided, seller-specific requirements and values are populated within the product type definition schema, such as brand names associated with the selling partner. (optional)
     * @param null|string $product_type_version
     *                                           The version of the Amazon product type to retrieve. Defaults to \&quot;LATEST\&quot;,. Prerelease versions of product type definitions may be retrieved with \&quot;RELEASE_CANDIDATE\&quot;. If no prerelease version is currently available, the \&quot;LATEST\&quot; live version will be provided. (optional, default to 'LATEST')
     * @param null|string $requirements
     *                                           The name of the requirements set to retrieve requirements for. (optional, default to 'LISTING')
     * @param null|string $requirements_enforced
     *                                           Identifies if the required attributes for a requirements set are enforced by the product type definition schema. Non-enforced requirements enable structural validation of individual attributes without all the required attributes being present (such as for partial updates). (optional, default to 'ENFORCED')
     * @param null|string $locale
     *                                           Locale for retrieving display labels and other presentation details. Defaults to the default language of the first marketplace in the request. (optional, default to 'DEFAULT')
     *
     * @throws \InvalidArgumentException
     */
    public function getDefinitionsProductTypeAsyncWithHttpInfo(
        string $product_type,
        array $marketplace_ids,
        ?string $seller_id = null,
        ?string $product_type_version = 'LATEST',
        ?string $requirements = 'LISTING',
        ?string $requirements_enforced = 'ENFORCED',
        ?string $locale = 'DEFAULT',
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeDefinition';
        $request = $this->getDefinitionsProductTypeRequest($product_type, $marketplace_ids, $seller_id, $product_type_version, $requirements, $requirements_enforced, $locale);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'DefinitionsApi-getDefinitionsProductType');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getDefinitionsProductTypeRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getDefinitionsProductType'.
     *
     * @param string      $product_type
     *                                           The Amazon product type name. (required)
     * @param string[]    $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. Note: This parameter is limited to one marketplaceId at this time. (required)
     * @param null|string $seller_id
     *                                           A selling partner identifier. When provided, seller-specific requirements and values are populated within the product type definition schema, such as brand names associated with the selling partner. (optional)
     * @param null|string $product_type_version
     *                                           The version of the Amazon product type to retrieve. Defaults to \&quot;LATEST\&quot;,. Prerelease versions of product type definitions may be retrieved with \&quot;RELEASE_CANDIDATE\&quot;. If no prerelease version is currently available, the \&quot;LATEST\&quot; live version will be provided. (optional, default to 'LATEST')
     * @param null|string $requirements
     *                                           The name of the requirements set to retrieve requirements for. (optional, default to 'LISTING')
     * @param null|string $requirements_enforced
     *                                           Identifies if the required attributes for a requirements set are enforced by the product type definition schema. Non-enforced requirements enable structural validation of individual attributes without all the required attributes being present (such as for partial updates). (optional, default to 'ENFORCED')
     * @param null|string $locale
     *                                           Locale for retrieving display labels and other presentation details. Defaults to the default language of the first marketplace in the request. (optional, default to 'DEFAULT')
     *
     * @throws \InvalidArgumentException
     */
    public function getDefinitionsProductTypeRequest(
        string $product_type,
        array $marketplace_ids,
        ?string $seller_id = null,
        ?string $product_type_version = 'LATEST',
        ?string $requirements = 'LISTING',
        ?string $requirements_enforced = 'ENFORCED',
        ?string $locale = 'DEFAULT'
    ): Request {
        // verify the required parameter 'product_type' is set
        if (null === $product_type || (is_array($product_type) && 0 === count($product_type))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $product_type when calling getDefinitionsProductType'
            );
        }
        // verify the required parameter 'marketplace_ids' is set
        if (null === $marketplace_ids || (is_array($marketplace_ids) && 0 === count($marketplace_ids))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $marketplace_ids when calling getDefinitionsProductType'
            );
        }

        $resourcePath = '/definitions/2020-09-01/productTypes/{productType}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $seller_id,
            'sellerId', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $marketplace_ids,
            'marketplaceIds', // param base name
            'array', // openApiType
            'form', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $product_type_version,
            'productTypeVersion', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $requirements,
            'requirements', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $requirements_enforced,
            'requirementsEnforced', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $locale,
            'locale', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);

        // path params
        if (null !== $product_type) {
            $resourcePath = str_replace(
                '{productType}',
                ObjectSerializer::toPathValue($product_type),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation searchDefinitionsProductTypes.
     *
     * @param string[]      $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. (required)
     * @param null|string[] $keywords
     *                                           A comma-delimited list of keywords to search product types. **Note:** Cannot be used with &#x60;itemName&#x60;. (optional)
     * @param null|string   $item_name
     *                                           The title of the ASIN to get the product type recommendation. **Note:** Cannot be used with &#x60;keywords&#x60;. (optional)
     * @param null|string   $locale
     *                                           The locale for the display names in the response. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $search_locale
     *                                           The locale used for the &#x60;keywords&#x60; and &#x60;itemName&#x60; parameters. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function searchDefinitionsProductTypes(
        array $marketplace_ids,
        ?array $keywords = null,
        ?string $item_name = null,
        ?string $locale = null,
        ?string $search_locale = null,
        ?string $restrictedDataToken = null
    ): ProductTypeList {
        list($response) = $this->searchDefinitionsProductTypesWithHttpInfo($marketplace_ids, $keywords, $item_name, $locale, $search_locale, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation searchDefinitionsProductTypesWithHttpInfo.
     *
     * @param string[]      $marketplace_ids
     *                                           A comma-delimited list of Amazon marketplace identifiers for the request. (required)
     * @param null|string[] $keywords
     *                                           A comma-delimited list of keywords to search product types. **Note:** Cannot be used with &#x60;itemName&#x60;. (optional)
     * @param null|string   $item_name
     *                                           The title of the ASIN to get the product type recommendation. **Note:** Cannot be used with &#x60;keywords&#x60;. (optional)
     * @param null|string   $locale
     *                                           The locale for the display names in the response. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $search_locale
     *                                           The locale used for the &#x60;keywords&#x60; and &#x60;itemName&#x60; parameters. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeList, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function searchDefinitionsProductTypesWithHttpInfo(
        array $marketplace_ids,
        ?array $keywords = null,
        ?string $item_name = null,
        ?string $locale = null,
        ?string $search_locale = null,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->searchDefinitionsProductTypesRequest($marketplace_ids, $keywords, $item_name, $locale, $search_locale);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'DefinitionsApi-searchDefinitionsProductTypes');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->searchDefinitionsProductTypesRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeList' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeList' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeList', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\productTypeDefinitions\v2020_09_01\ErrorList',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation searchDefinitionsProductTypesAsync.
     *
     * @param string[]      $marketplace_ids
     *                                       A comma-delimited list of Amazon marketplace identifiers for the request. (required)
     * @param null|string[] $keywords
     *                                       A comma-delimited list of keywords to search product types. **Note:** Cannot be used with &#x60;itemName&#x60;. (optional)
     * @param null|string   $item_name
     *                                       The title of the ASIN to get the product type recommendation. **Note:** Cannot be used with &#x60;keywords&#x60;. (optional)
     * @param null|string   $locale
     *                                       The locale for the display names in the response. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $search_locale
     *                                       The locale used for the &#x60;keywords&#x60; and &#x60;itemName&#x60; parameters. Defaults to the primary locale of the marketplace. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function searchDefinitionsProductTypesAsync(
        array $marketplace_ids,
        ?array $keywords = null,
        ?string $item_name = null,
        ?string $locale = null,
        ?string $search_locale = null
    ): PromiseInterface {
        return $this->searchDefinitionsProductTypesAsyncWithHttpInfo($marketplace_ids, $keywords, $item_name, $locale, $search_locale)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation searchDefinitionsProductTypesAsyncWithHttpInfo.
     *
     * @param string[]      $marketplace_ids
     *                                       A comma-delimited list of Amazon marketplace identifiers for the request. (required)
     * @param null|string[] $keywords
     *                                       A comma-delimited list of keywords to search product types. **Note:** Cannot be used with &#x60;itemName&#x60;. (optional)
     * @param null|string   $item_name
     *                                       The title of the ASIN to get the product type recommendation. **Note:** Cannot be used with &#x60;keywords&#x60;. (optional)
     * @param null|string   $locale
     *                                       The locale for the display names in the response. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $search_locale
     *                                       The locale used for the &#x60;keywords&#x60; and &#x60;itemName&#x60; parameters. Defaults to the primary locale of the marketplace. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function searchDefinitionsProductTypesAsyncWithHttpInfo(
        array $marketplace_ids,
        ?array $keywords = null,
        ?string $item_name = null,
        ?string $locale = null,
        ?string $search_locale = null,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\productTypeDefinitions\v2020_09_01\ProductTypeList';
        $request = $this->searchDefinitionsProductTypesRequest($marketplace_ids, $keywords, $item_name, $locale, $search_locale);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'DefinitionsApi-searchDefinitionsProductTypes');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->searchDefinitionsProductTypesRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'searchDefinitionsProductTypes'.
     *
     * @param string[]      $marketplace_ids
     *                                       A comma-delimited list of Amazon marketplace identifiers for the request. (required)
     * @param null|string[] $keywords
     *                                       A comma-delimited list of keywords to search product types. **Note:** Cannot be used with &#x60;itemName&#x60;. (optional)
     * @param null|string   $item_name
     *                                       The title of the ASIN to get the product type recommendation. **Note:** Cannot be used with &#x60;keywords&#x60;. (optional)
     * @param null|string   $locale
     *                                       The locale for the display names in the response. Defaults to the primary locale of the marketplace. (optional)
     * @param null|string   $search_locale
     *                                       The locale used for the &#x60;keywords&#x60; and &#x60;itemName&#x60; parameters. Defaults to the primary locale of the marketplace. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function searchDefinitionsProductTypesRequest(
        array $marketplace_ids,
        ?array $keywords = null,
        ?string $item_name = null,
        ?string $locale = null,
        ?string $search_locale = null
    ): Request {
        // verify the required parameter 'marketplace_ids' is set
        if (null === $marketplace_ids || (is_array($marketplace_ids) && 0 === count($marketplace_ids))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $marketplace_ids when calling searchDefinitionsProductTypes'
            );
        }

        $resourcePath = '/definitions/2020-09-01/productTypes';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $keywords,
            'keywords', // param base name
            'array', // openApiType
            'form', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $marketplace_ids,
            'marketplaceIds', // param base name
            'array', // openApiType
            'form', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $item_name,
            'itemName', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $locale,
            'locale', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $search_locale,
            'searchLocale', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);

        $headers = $this->headerSelector->selectHeaders(
            ['application/json'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Create http client option.
     *
     * @return array of http client options
     *
     * @throws \RuntimeException on file opening failure
     */
    protected function createHttpClientOption(): array
    {
        $options = [];
        if ($this->config->getDebug()) {
            $options[RequestOptions::DEBUG] = fopen($this->config->getDebugFile(), 'a');
            if (!$options[RequestOptions::DEBUG]) {
                throw new \RuntimeException('Failed to open the debug file: '.$this->config->getDebugFile());
            }
        }

        return $options;
    }
}
